import { reactive } from '../reactive/reactive'
import { effect } from '../reactive/effect'
import { queueJob } from './scheduler'
import { normalizeVNode } from './vnode'
import { compile } from '../compiler/compile'

function updateProps(instance, vnode) {
    // Component是组件对象，vnodeProps是h函数的第二个参数，也就是虚拟dom的props
    const { type: Component, props: vnodeProps } = vnode
    const props = instance.props = {}
    const attrs = instance.attrs = {}
    for (const key in vnodeProps) {
        // Component.props有很多种写法，这里默认为数组写法
        // props:['title','age']
        if (Component.props?.includes(key)) {
            props[key] = vnodeProps[key]
        } else {
            attrs[key] = vnodeProps[key]
        }
    }
    instance.props = reactive(instance.props)
}

// 把组件上的属性放到子树上
function fallThrough(instance, subTree) {
    if (Object.keys(instance.attrs).length) {
        subTree.props = {
            ...subTree.props,
            ...instance.attrs
        }
    }
}

export function mountComponent(vnode, container, anchor, patch) {
    // Component有两个vnode，一个是他自身，另外一个是他的render函数创建的
    // Component是组件对象
    const { type: Component } = vnode
    console.log(vnode);
    const instance = (vnode.component = {
        props: null,
        attrs: null,//组件身上的属性
        setupState: null,//组件本身定义的状态,和父组件传递的
        ctx: null,//setup函数的上下文
        mount: null,
        update: null,
        subTree: null,
        isMounted: false,//标致组件是否已经挂载过了
        next: null
    })
    // 更新组件的Props
    updateProps(instance, vnode)

    // setup函数第一个参数是父组件传来的props，第二个参数是上下文，里面包括attrs,slots,emit这里只实现了attrs
    instance.setupState = Component.setup?.(instance.props, { attrs: instance.attrs })
    // ctx：组件对象render方法的参数
    instance.ctx = {
        ...instance.props, // 传递的props
        ...instance.setupState, // 组件内部定义的数据
    }
    // 没有render，是template
    if (!Component.render && Component.template) {
        let { template } = Component
        // 选择器

        if (template[0] === '#') {
            const el = document.querySelector(template)
            template = el ? el.innerHTML : ''
        }
        const code = compile(template)
        Component.render = new Function('ctx', code)
        console.log(Component.render);
    }
    // 修改state中的值，要进行dom更新
    console.log(instance);
    instance.update = effect(() => {
        if (!instance.isMounted) {
            // 第一次mount
            // subTree子树
            // render函数在这用到了state中的值，所以state中的值发生改变时，effect会调用
            const subTree = (instance.subTree = normalizeVNode(Component.render(instance.ctx)))
            fallThrough(instance, subTree)
            console.log('patch前');
            patch(null, subTree, container, anchor)
            vnode.el = subTree.el
            instance.isMounted = true
        } else {
            if (instance.next) {
                // 被动更新
                vnode = instance.next
                instance.next = null
                updateProps(instance, vnode)
                instance.ctx = {
                    ...instance.props,
                    ...instance.setupState
                }
            }

            // 更新
            // 拿到之前的subTree
            const prev = instance.subTree
            // subTree子树
            const subTree = (instance.subTree = normalizeVNode(Component.render(instance.ctx)))

            fallThrough(instance, subTree)
            patch(prev, subTree, container, anchor)
            vnode.el = subTree.el

        }

    }, {
        scheduler: queueJob
    })
}